package io.github.talelin.latticy.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.github.talelin.autoconfigure.exception.NotFoundException;
import io.github.talelin.latticy.common.mybatis.Page;
import io.github.talelin.latticy.dto.category.CategoryDTO;
import io.github.talelin.latticy.dto.category.CategoryPageDTO;
import io.github.talelin.latticy.dto.category.UpdateCategoryDTO;
import io.github.talelin.latticy.mapper.CategoryMapper;
import io.github.talelin.latticy.model.BaseModel;
import io.github.talelin.latticy.model.CategoryDO;
import io.github.talelin.latticy.service.CategoryService;
import io.github.talelin.latticy.vo.CategoryVO;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * ClassName CategoryServiceImpl
 * Description
 * Create by zcy
 * Date 2022-06-09
 */
@Service
public class CategoryServiceImpl extends ServiceImpl<CategoryMapper, CategoryDO> implements CategoryService {

    @Override
    public void createCategory(CategoryDTO categoryDTO) {
        Assert.isFalse(this.checkCategoryExistByName(categoryDTO.getCategoryName()), "18506");
        Assert.isFalse(this.checkCategoryExistByEnglishName(categoryDTO.getCategoryEnglishName()), "18507");
        CategoryDO categoryDO = new CategoryDO(categoryDTO);
        Assert.isTrue(this.baseMapper.insert(categoryDO) > 0, "18503");
    }

    @Override
    public void updateCategory(Integer id, UpdateCategoryDTO updateCategoryDTO) {
        Assert.isFalse(this.checkCategoryExistByName(id, updateCategoryDTO.getCategoryName()), "18506");
        Assert.isFalse(this.checkCategoryExistByEnglishName(id, updateCategoryDTO.getCategoryEnglishName()), "18507");
        CategoryDO categoryDO = new CategoryDO(id, updateCategoryDTO);
        Assert.isTrue(this.baseMapper.updateById(categoryDO) > 0, "18504");
    }

    @Override
    public void deleteCategory(Integer id) {
        CategoryDO category = this.getById(id);
        Optional.ofNullable(category).orElseThrow(() -> new NotFoundException(18508));
        // 查找当前父分类下有无子分类，如有则不能删除
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getParentId, id);
        wrapper.last("limit 1");
        CategoryDO subCategory = this.baseMapper.selectOne(wrapper);
        if (Objects.nonNull(subCategory)) {
            throw new NotFoundException(18509);
        }
        Assert.isTrue(this.getBaseMapper().deleteById(id) > 0, "18505");
    }

    @Override
    public IPage<CategoryDO> getCategoryPage(CategoryPageDTO categoryPageDTO) {
        return this.baseMapper.selectPage(new Page<>(categoryPageDTO.getPage(), categoryPageDTO.getCount()),
                new LambdaQueryWrapper<CategoryDO>().like(StrUtil.isNotEmpty(categoryPageDTO.getSearch()), CategoryDO::getCategoryName, categoryPageDTO.getSearch())
                        .or().like(StrUtil.isNotEmpty(categoryPageDTO.getSearch()), CategoryDO::getCategoryEnglishName, categoryPageDTO.getSearch())
        );
    }

    @Override
    public IPage<CategoryDO> getCategoryPage(Integer count, Integer page, Integer root) {
        Page<CategoryDO> pager = new Page<>(page, count);
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getLevel, root);
        return this.getBaseMapper().selectPage(pager, wrapper);
    }

    @Override
    public IPage<CategoryDO> getSubCategoriesByPage(Integer count, Integer page, Integer id) {
        Page<CategoryDO> pager = new Page<>(page, count);
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getParentId, id);
        return this.getBaseMapper().selectPage(pager, wrapper);
    }


    @Override
    public List<CategoryVO> getCategoryTree() {
        List<CategoryDO> categoryDOList = this.baseMapper.selectList(new LambdaQueryWrapper<>());
        //判断是否有数据
        if (CollUtil.isEmpty(categoryDOList)) {
            return new ArrayList<>();
        }
        List<CategoryVO> roots = categoryDOList.stream().filter(c -> c.getParentId() == 0).map(this::copyPropVO).collect(Collectors.toList());
        List<CategoryVO> subs = categoryDOList.stream().filter(c -> c.getParentId() != 0).map(this::copyPropVO).collect(Collectors.toList());
        return roots.stream().filter((category) -> category.getParentId() == 0).map((category) -> {
            category.setChildren(getChildren(category, subs));
            return category;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Integer> findParentId(Integer id) {
        List<CategoryDO> categorys = this.baseMapper.findParentId(id);
        List<Integer> ids = categorys.stream().map(BaseModel::getId).collect(Collectors.toList());
        Collections.reverse(ids);
        return ids;
    }

    @Override
    public boolean checkCategoryExistByName(int id, String categoryName) {
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getCategoryName, categoryName).ne(CategoryDO::getId, id);
        return this.count(wrapper) > 0;
    }

    @Override
    public boolean checkCategoryExistByName(String categoryName) {
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getCategoryName, categoryName);
        return this.count(wrapper) > 0;
    }

    @Override
    public boolean checkCategoryExistByEnglishName(String categoryEnglishName) {
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getCategoryEnglishName, categoryEnglishName);
        return this.count(wrapper) > 0;
    }

    @Override
    public boolean checkCategoryExistByEnglishName(int id, String categoryEnglishName) {
        QueryWrapper<CategoryDO> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(CategoryDO::getCategoryEnglishName, categoryEnglishName).ne(CategoryDO::getId, id);
        return this.count(wrapper) > 0;
    }

    /**
     * 递归查找所有菜单的子菜单
     *
     * @param root
     * @param subs
     * @return
     */
    private List<CategoryVO> getChildren(CategoryVO root, List<CategoryVO> subs) {
        return subs.stream().filter(categoryEntity -> {
            return categoryEntity.getParentId().equals(root.getId());
        }).map(category -> {
            //查询子品类
            category.setChildren(getChildren(category, subs));
            return category;
        }).collect(Collectors.toList());
    }

    private CategoryVO copyPropVO(CategoryDO categoryDO) {
        CategoryVO category = new CategoryVO();
        BeanUtils.copyProperties(categoryDO, category);
        category.setValue(categoryDO.getId());
        category.setLabel(categoryDO.getCategoryName());
        return category;
    }

}
